57. 绘制散点图

⭐ 散点图:揭示两个变量之间的关系

散点图(Scatter Plot)是展示两个变量关系最直观的工具

在商业与金融分析中,散点图帮助我们:

  • 识别相关性:正相关、负相关、无相关
  • 发现模式:线性、非线性、聚类
  • 检测异常值:远离主群体的数据点
  • 验证假设:风险与收益、规模与回报的关系

⭐ 散点图的数学基础:相关系数

散点图展示两个变量 \((X, Y)\) 的关系:

\[ \{(x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n)\} \]

Pearson 相关系数衡量线性相关程度:

\[ \rho_{XY} = \frac{\sum(x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum(x_i - \bar{x})^2}\sqrt{\sum(y_i - \bar{y})^2}} \]

⭐ 相关系数的视觉特征

相关系数 散点图特征 含义
\(\rho \approx 1\) 点从左下到右上,直线上升 强正相关
\(\rho \approx -1\) 点从左上到右下,直线下降 强负相关
\(\rho \approx 0\) 点散乱,无明显方向 无线性相关

⭐ 平台任务解答代码

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
#任务一
import pandas as pd
index_closeprice = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726722771060.xlsx") #导入数据
index_closeprice["日期"] = pd.to_datetime(index_closeprice["日期"] , format='%Y%m%d')  # 转换为日期时间格式
index_closeprice.set_index("日期",inplace=True)  # 将日期列设为index_closeprice数据框的索引
index_return = index_closeprice/index_closeprice.shift(1)-1 #计算股指的周涨跌幅 
index_return = index_return.dropna() #删除缺失值
print(index_return.corr())  #计算指数周涨跌幅的相关系数


#任务二
import matplotlib.pyplot as plt
import pandas as pd  # 导入Pandas数据分析库
plt.rcParams['font.sans-serif']=['SimHei']   # 用黑体显示中文
plt.rcParams['axes.unicode_minus']=False     # 正常显示负号


index_closeprice = pd.read_excel("https://huoran.oss-cn-shenzhen.aliyuncs.com/1726722771060.xlsx") #导入数据
index_closeprice["日期"] = pd.to_datetime(index_closeprice["日期"] , format='%Y%m%d')  # 转换为日期时间格式
index_closeprice.set_index("日期",inplace=True)  # 将日期列设为index_closeprice数据框的索引
index_return = index_closeprice/index_closeprice.shift(1)-1 #计算股指的周涨跌幅
index_return = index_return.dropna() #删除缺失值
plt.figure(figsize=(11,6))  # 创建图形画布
plt.subplot(1,2,1)  #第1行、第1列子图
plt.scatter(x=index_return.iloc[:,-1],y=index_return.iloc[:,0],c="c",marker="o")    #创业板指与上证综指的散点图 
plt.xlabel(u"创业板指",fontsize=13)  # 设置X轴标签
plt.ylabel(u"上证综指",fontsize=13,rotation=90)  # 设置Y轴标签
plt.xticks(fontsize=13)  # 设置X轴刻度标签
plt.yticks(fontsize=13)  # 设置Y轴刻度标签
plt.title(u"创业板指与上证综指的散点图",fontsize=15)  # 设置图表标题
plt.grid(True)  # 显示网格线
plt.subplot(1,2,2,sharex=plt.subplot(1,2,1),sharey=plt.subplot(1,2,1))  #与第一个子图共用X轴和Y轴
plt.scatter(x=index_return.iloc[:,-1],y=index_return.iloc[:,1],c="c",marker="o")  # 绑制散点图
plt.xlabel(u"创业板指",fontsize=13)  # 设置X轴标签
plt.ylabel(u"深证成指",fontsize=13,rotation=90)  # 设置Y轴标签
plt.xticks(fontsize=13)  # 设置X轴刻度标签
plt.yticks(fontsize=13)  # 设置Y轴刻度标签
plt.title(u"创业板指与深证成指的散点图",fontsize=15)  # 设置图表标题
plt.grid(True)  # 显示网格线
plt.savefig("1.png")  # 保存图形至文件
          上证综指      深圳成指      创业板指
上证综指  1.000000  0.886014  0.774132
深圳成指  0.886014  1.000000  0.946785
创业板指  0.774132  0.946785  1.000000
Listing 1

⭐ 基础散点图:风险与收益的关系

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建风险-收益数据
np.random.seed(42)
n_stocks = 50

# 模拟: 风险越高, 收益越高(正相关)
risk = np.random.uniform(0.1, 0.4, n_stocks)
return_mean = 0.03 + 0.5 * risk + np.random.normal(0, 0.02, n_stocks)

# 绘制散点图
plt.figure(figsize=(10, 6))
plt.scatter(risk, return_mean, s=100, alpha=0.7, color='#2E86AB', edgecolors='white')

# 添加拟合线
z = np.polyfit(risk, return_mean, 1)
p = np.poly1d(z)
plt.plot(risk, p(risk), 'r--', linewidth=2, label=f'拟合线: y={z[0]:.2f}x+{z[1]:.3f}')

plt.xlabel('风险(标准差)', fontsize=12)
plt.ylabel('期望收益率', fontsize=12)
plt.title('风险与收益的关系', fontsize=16, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# 计算相关系数
correlation = np.corrcoef(risk, return_mean)[0, 1]
print(f'风险与收益的相关系数: {correlation:.4f}')
Figure 1: 基础散点图——风险与收益的关系
风险与收益的相关系数: 0.9167

⭐ scatter 关键参数详解

参数 说明 示例
s 点大小(面积) s=100 适合大多数场景
alpha 透明度,重叠点仍可见 alpha=0.7
color 点颜色 color='#2E86AB'
edgecolors 点边缘颜色 edgecolors='white' 更清晰
marker 点形状 marker='o' 圆形
linewidths 边缘线宽 linewidths=1.5

⭐ 多组散点图:不同行业的对比

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建三个行业的数据
np.random.seed(42)
industries = {
    '银行': {'risk': np.random.uniform(0.1, 0.2, 15),
             'return': np.random.normal(0.04, 0.01, 15)},
    '科技': {'risk': np.random.uniform(0.25, 0.45, 15),
             'return': np.random.normal(0.08, 0.02, 15)},
    '公用事业': {'risk': np.random.uniform(0.08, 0.15, 15),
                 'return': np.random.normal(0.03, 0.008, 15)}
}

colors = {'银行': '#E3120B', '科技': '#008080', '公用事业': '#F0A700'}

plt.figure(figsize=(10, 6))
for industry, data in industries.items():
    plt.scatter(data['risk'], data['return'],
                s=120, alpha=0.7, color=colors[industry],
                edgecolors='white', label=industry, linewidths=1.5)

plt.xlabel('风险(标准差)', fontsize=12)
plt.ylabel('收益率', fontsize=12)
plt.title('不同行业风险-收益特征', fontsize=16, fontweight='bold')
plt.legend(fontsize=11, loc='upper left')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Figure 2: 多组散点图——不同行业公司的对比

⭐ 多组散点图的可视化策略

绘制多组数据时,需注意以下要点:

  • 颜色区分:每个类别用不同颜色,确保色差明显
  • 图例清晰:标注每个颜色对应的含义
  • 点大小一致:便于比较各组的密度分布
  • 边缘线:白色边缘使重叠点更清晰
  • 透明度alpha=0.7 让重叠区域可辨识

⭐ 气泡图:三维数据展示

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建三维数据(风险、收益、市值)
np.random.seed(42)
n = 30
data = pd.DataFrame({
    '风险': np.random.uniform(0.1, 0.4, n),
    '收益': np.random.normal(0.05, 0.02, n),
    '市值': np.random.uniform(50, 500, n)
})

plt.figure(figsize=(10, 6))
scatter = plt.scatter(data['风险'], data['收益'],
                      s=data['市值'] / 2, c=data['市值'],
                      cmap='Blues', alpha=0.6,
                      edgecolors='white', linewidths=1.5)

cbar = plt.colorbar(scatter)
cbar.set_label('市值(亿元)', fontsize=11)

# 标注市值最大的3家公司
top3 = data.nlargest(3, '市值')
for idx, row in top3.iterrows():
    plt.annotate(f'市值{row["市值"]:.0f}亿',
                 (row['风险'], row['收益']),
                 xytext=(5, 5), textcoords='offset points',
                 fontsize=9, bbox=dict(boxstyle='round,pad=0.3',
                                       facecolor='yellow', alpha=0.3))

plt.xlabel('风险(标准差)', fontsize=12)
plt.ylabel('收益率', fontsize=12)
plt.title('风险-收益-市值关系', fontsize=16, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Figure 3: 气泡图——风险、收益与市值的关系

⭐ 气泡图的设计要点

  • 第三维度:气泡大小表示第三个变量(如市值)
  • 大小比例:避免气泡过大遮挡,过小看不见
  • 颜色映射:可用颜色强化第三维信息(双重编码)
  • 标注关键点:只标注重要数据点,避免文字拥挤
  • 颜色条:添加 colorbar 说明颜色与数值的映射

⭐ 散点图矩阵:多变量关系探索

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from pandas.plotting import scatter_matrix

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

np.random.seed(42)
df_multi = pd.DataFrame({
    'PE': np.random.uniform(10, 60, 100),
    'PB': np.random.uniform(0.5, 10, 100),
    'ROE': np.random.uniform(0.05, 0.35, 100),
    '收益率': np.random.normal(0.05, 0.02, 100)
})

fig = plt.figure(figsize=(12, 12))
axes = scatter_matrix(df_multi, alpha=0.6, diagonal='kde',
                      c='#2E86AB', edgecolors='white',
                      figsize=(12, 12))

plt.suptitle('多变量散点图矩阵', fontsize=16, fontweight='bold', y=1.02)
plt.tight_layout()
plt.show()

print('相关系数矩阵:')
print(df_multi.corr().round(3))
相关系数矩阵:
        PE     PB    ROE    收益率
PE   1.000 -0.034 -0.038  0.120
PB  -0.034  1.000 -0.146  0.044
ROE -0.038 -0.146  1.000  0.085
收益率  0.120  0.044  0.085  1.000
<Figure size 1152x1152 with 0 Axes>
(a) 散点图矩阵——多变量关系探索
(b)
Figure 4

⭐ 散点图矩阵的应用场景

散点图矩阵可快速探索多个变量两两之间的关系:

  • 探索性数据分析(EDA):快速发现变量间的关系模式
  • 特征选择:识别高度相关的特征,避免多重共线性
  • 对角线diagonal='kde' 显示各变量的核密度估计
  • 多元正态性检验:判断联合分布是否近似正态

⭐ 回归线与置信区间

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 创建数据
np.random.seed(42)
x = np.random.uniform(0, 10, 100)
y = 2 + 1.5 * x + np.random.normal(0, 2, 100)

# 绘制带回归线的散点图
plt.figure(figsize=(10, 6))
sns.regplot(x=x, y=y,
            scatter_kws={'s': 80, 'alpha': 0.6, 'color': '#2E86AB'},
            line_kws={'color': '#E3120B', 'linewidth': 2.5},
            ci=95)

plt.xlabel('X变量', fontsize=12)
plt.ylabel('Y变量', fontsize=12)
plt.title('线性回归与置信区间', fontsize=16, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# 计算回归统计
from scipy import stats
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
print(f'回归方程: y = {slope:.2f}x + {intercept:.2f}')
print(f'R² = {r_value**2:.4f}')
print(f'p值 = {p_value:.4e}')
Figure 5: 散点图与回归线——包含置信区间
回归方程: y = 1.41x + 2.43
R² = 0.8434
p值 = 3.1046e-41

⭐ 置信区间的含义

  • 95%置信区间:有 95% 的把握真实回归线在此阴影区间内
  • 形状特征:两端较宽(数据少时不确定性大),中间较窄
  • sns.regplot:Seaborn 自动计算并绘制置信区间
  • ci=95:设置置信水平,常用 90%、95%、99%

⭐ 金融应用:CAPM 模型可视化

import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 模拟市场收益率和个股收益率
np.random.seed(42)
n_obs = 60
market_return = np.random.normal(0.0008, 0.015, n_obs)
beta = 1.2
alpha = 0.0002
stock_return = alpha + beta * market_return + np.random.normal(0, 0.01, n_obs)

# 绘制证券特征线
plt.figure(figsize=(10, 6))
plt.scatter(market_return, stock_return,
            s=80, alpha=0.6, color='#2E86AB', edgecolors='white')

# 添加拟合线
z = np.polyfit(market_return, stock_return, 1)
p = np.poly1d(z)
x_line = np.linspace(market_return.min(), market_return.max(), 100)
plt.plot(x_line, p(x_line), 'r-', linewidth=2.5, label='证券特征线(SML)')

# 添加理论线(alpha=0)
plt.plot(x_line, beta * x_line, 'g--', linewidth=2, alpha=0.7, label='理论线(α=0)')

plt.xlabel('市场收益率 $R_m$', fontsize=12)
plt.ylabel('股票收益率 $R_i$', fontsize=12)
plt.title(f'CAPM模型: β={beta:.2f}, α={alpha:.4f}', fontsize=16, fontweight='bold')
plt.legend(fontsize=11)
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
plt.axvline(x=0, color='k', linestyle='-', linewidth=0.5)
plt.tight_layout()
plt.show()

# 统计量
correlation = np.corrcoef(market_return, stock_return)[0, 1]
r_squared = correlation ** 2
print(f'Beta (β): {z[0]:.2f}')
print(f'Alpha (α): {z[1]:.4f}')
print(f'R²: {r_squared:.4f}')
Figure 6: 证券特征线——CAPM模型可视化
Beta (β): 1.25
Alpha (α): 0.0002
R²: 0.7667

⭐ CAPM 模型核心概念

CAPM 公式\(R_i = \alpha + \beta \cdot R_m + \epsilon\)

参数 含义 解读
\(\beta > 1\) 进攻型股票 波动大于市场
\(\beta < 1\) 防御型股票 波动小于市场
\(\beta = 1\) 与市场同步 跟踪市场走势
\(\alpha > 0\) 正超额收益 跑赢市场基准

⭐ 本章小结

图表类型 适用场景 核心函数
基础散点图 两变量关系 plt.scatter()
多组散点图 分类对比 循环 + label
气泡图 三维数据展示 s= 控制大小
散点图矩阵 多变量探索 scatter_matrix()
回归散点图 线性关系验证 sns.regplot()
CAPM 特征线 金融建模 拟合 + 理论线